#pragma once
#include "KhaosTypes.h"

namespace Khaos
{
    //////////////////////////////////////////////////////////////////////////
    template<class T, const size_t n, const bool fastCopy>
    class Array : public AllocatedObject
    {
    public:
        typedef const T(&ConstRefType)[n];
        typedef T(&RefType)[n];

    public:
        Array() {}

        Array( const Array& oth )
        {
            _copy( oth.m_val, IntToType<fastCopy>() );
        }

        explicit Array( const T* v )
        {
            _copy( v, IntToType<fastCopy>() );
        }

        Array& operator=( const Array& oth )
        {
            if ( this != &oth )
                _copy( oth.m_val, IntToType<fastCopy>() );
            return *this;
        }

        Array& operator=( const T* v )
        {
            _copy( v, IntToType<fastCopy>() );
            return *this;
        }

        const T& operator[]( size_t i ) const
        {
            khaosAssert( i < n );
            return m_val[i];
        }

        T& operator[]( size_t i ) 
        {
            khaosAssert( i < n );
            return m_val[i];
        }

        operator ConstRefType() const
        {
            return m_val;
        }

        operator RefType()
        {
            return m_val;
        }

    private:
        void _copy( const T* v, IntToType<true> )
        {
            memcpy( m_val, v, sizeof(m_val) );
        }

        void _copy( const T* v, IntToType<false> )
        {
            for ( size_t i = 0; i < n; ++i )
                m_val[i] = v[i];
        }

    private:
        T m_val[n];
    };


    //-------------------------------------------------------------------------------
    template<class T, uint32_t N>
    class SimpleList : public AllocatedObject
    {
    public:
        const T& at(uint32_t i) const
        {
            khaosAssert(i < m_size);
            return m_vals[i];
        }

        T& at(uint32_t i)
        {
            khaosAssert(i < m_size);
            return m_vals[i];
        }

        const T& atRaw(uint32_t i) const
        {
            khaosAssert(i < N);
            return m_vals[i];
        }

        T& atRaw(uint32_t i)
        {
            khaosAssert(i < N);
            return m_vals[i];
        }

        void pushBack(const T& val)
        {
            khaosAssert(m_size < KHAOS_ARRAY_SIZE(m_vals));
            m_vals[m_size] = val;
            ++m_size;
        }

        uint32_t getSize() const
        {
            return m_size;
        }

        uint32_t getMaxSize() const
        {
            return N;
        }

        void clear()
        {
            m_size = 0;
        }

    private:
        T m_vals[N];
        uint32_t m_size = 0;
    };

}

